/**
 * javaHispano 2008
 */
package org.javahispano.jwitter.services.pojo;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.imageio.ImageIO;

import org.apache.log4j.Logger;
import org.javahispano.jwitter.data.dao.UsuarioDao;
import org.javahispano.jwitter.domain.Authority;
import org.javahispano.jwitter.domain.Usuario;
import org.javahispano.jwitter.services.RegistroService;
import org.javahispano.jwitter.view.command.UsuarioCommand;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.providers.encoding.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
 * @author javaHispano
 * Servicio Spring, se anota con el estereotipo Service para que el application context pueda encontrarlo
 * y configurarlo automaticamente
 */
@Service
public class RegistroServiceImpl implements RegistroService {
	
	private static Logger log = Logger.getLogger(RegistroService.class.getName());
	
	@Autowired
	private UsuarioDao usuarioDao;		
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	/**
	 * Se anota con "@Transacitional" para que Spring abra una
	 * transaccion usando el Transaction Manager definido al 
	 * ejecutar este metodo
	 */
	@Override
	@Transactional
	public void registrarUsuario(UsuarioCommand command) {
		Usuario usuario = new Usuario();
		if(command.getArchivoFoto().getSize() > 0 ){
			log.info("Hay foto-> " + command.getArchivoFoto());
			guardarFoto(command);
		}else{
			log.info("no Hay foto :-( " );
		}
			
						
		BeanUtils.copyProperties(command, usuario);		
		usuario.setEnabled(true);
		usuario.setFechaRegistro(new Date());
		//Hacemos el hash de la contrasena usando como salt el username
		usuario.setPassword(passwordEncoder.encodePassword(usuario.getPassword(), usuario.getUsername()));		
		List<Authority> authorities = new ArrayList<Authority>();
		Authority auth = new Authority();
		auth.setAuthority(Authority.ROLE_USER);
		auth.setUsuario(usuario);
		authorities.add(auth);
		usuario.setAuthorities(authorities);	
		usuarioDao.persist(usuario);
		
	}

	public Usuario findById(String username) {
		return usuarioDao.findById(username);
	}
	
	public Collection<Usuario> ultimosUsuarios(int numUsuarios) {
		return usuarioDao.getUltimosUsuarios(numUsuarios);
	}
	
	@Transactional
	public void addContact(String usuario, String contacto) {
		Usuario u = usuarioDao.findById(usuario);
		Usuario c = usuarioDao.findById(contacto);
		
		if(c != null) {
			u.addContacto(c);
			usuarioDao.update(u);
		}
	}
	
	@Override
	public void guardarFoto(UsuarioCommand command) {
		MultipartFile fichero = command.getArchivoFoto();
		if(fichero.getSize()>0){
			
			//Obtenemos la extension del fichero
			String extension = fichero.getOriginalFilename().indexOf(".")!=-1?
			fichero.getOriginalFilename().substring(fichero.getOriginalFilename().lastIndexOf(".")).toLowerCase():"";										
			
			
			try {
				//Lo guardamos en un archivo temporal
				File fotoFile = File.createTempFile("jwitter", ".jpg");
				fotoFile.deleteOnExit();
				fichero.transferTo(fotoFile);								
				
				//escalamos la imagen
				resizeImage(fotoFile, extension);
				
				command.setFotoFile(getBytesFromFile(fotoFile));
			} catch (Exception e) {				
				log.error("Error al guardar la foto " + e);			
				throw new RuntimeException("Ocurrio un error al guardar la foto del usuario", e);
			}					
		}
		
	}

	
	
	/**
	 * Escala una foto a 48 x 48
	 * @param inputStream InputStream con la imagen
	 * @param extension Extension del archivo de imagen
	 * @return InputStream con la imagen escalada
	 */
	private void resizeImage(File inputFile, String extension) {		
		BufferedImage image;
		OutputStream out = null;
		log.info("Archivo->" + inputFile.length());
		try {
			image = ImageIO.read(inputFile);			
			BufferedImage thumbImage = new BufferedImage(48, 
	        		48, BufferedImage.TYPE_INT_RGB);
	        Graphics2D graphics2D = thumbImage.createGraphics();
	        graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
	          RenderingHints.VALUE_INTERPOLATION_BILINEAR);
	        graphics2D.drawImage(image, 0, 0, 48, 48, null);
	 
	        
	        out = new FileOutputStream(inputFile);
	        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
	        JPEGEncodeParam param = encoder.
	          getDefaultJPEGEncodeParam(thumbImage);
	        int quality = 100; 
	        quality = Math.max(0, Math.min(quality, 100));
	        param.setQuality((float)quality / 100.0f, false);
	        encoder.setJPEGEncodeParam(param);
	        encoder.encode(thumbImage);        
	        ImageIO.write(thumbImage, "jpeg" , out); 
				
		} catch (Exception e) {
			log.error("Error al escalar la imagen", e);
			throw new RuntimeException("Error al escalar la imagen.", e);
		}finally{
			if(out != null){
				try {
					out.close();
				} catch (IOException e) {			
					log.error(e);
				}
				
			}
		}
				
		
	}
	
	/**
	 * Obtiene la foto guardada del usuario.
	 * Si no existe, regresa una foto por defecto.
	 */
	@Override
	public byte[] recuperaFoto(String username) {
		Usuario u = usuarioDao.findById(username);
		byte[] bytes = null;
		File f = null;
		if(u != null){
			if(u.getFotoFile() != null){
				bytes  = u.getFotoFile();			
			}
		}
		if(bytes == null){
			try {
				f = new File(this.getClass().getResource("/persona.png").toURI());
				
				bytes = getBytesFromFile(f);
			} catch (Exception e) {				
				log.error(e);
				throw new RuntimeException("Error al recuperar foto por default. Revisa que el fichero persona.png este en tu classpath ", e);
			}
		}
		return bytes;
	}
	
	@Override
	public boolean existsEmail(String email) {		
		return usuarioDao.existsEmail(email);
	}


	@Override
	public boolean existsUsername(String username) {
		return usuarioDao.existsUsername(username);
	}
	
	private  byte[] getBytesFromFile(File file) throws IOException {
        InputStream is = new FileInputStream(file);
    
        // Get the size of the file
        long length = file.length();
    
        if (length > Integer.MAX_VALUE) {
            // File is too large
        }
    
        // Create the byte array to hold the data
        byte[] bytes = new byte[(int)length];
    
        // Read in the bytes
        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length
               && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
            offset += numRead;
        }
    
        // Ensure all the bytes have been read in
        if (offset < bytes.length) {
            throw new IOException("Could not completely read file "+file.getName());
        }
    
        // Close the input stream and return bytes
        is.close();
        return bytes;
    }

}
